<?php

/**
 * Albireo Kernel
 *
 * @copyright  Copyright (c) 2010 Albireo Solutions
 * @package    Kernel
 */
 
namespace KernelModule\LogsModule\PhpModule;

use Nette\Object;
use Nette\Environment;

//use Albireo\FileSystem\File;
//use Albireo\FileSystem\FileNotFoundException;
use Albireo\FileSystem\FileException;

use KernelModule\LogsModule\LogsException;

/**
 * Contains functions for processing the logs.
 *
 * @author Pavel
 */

class Process extends Base {

    private $processed;

    /**
     * Process the dirty log file into clean.
     *
     * @return boolean TRUE when whole file was processed, FALSE otherwise
     * @throws Albireo\FileSystem\FileException when the lock problem occures
     * or when the temporary files can't be deleted.
     */
    public function processDirty() {
        try {
            $this->initializeLogFiles();
        } catch (LogsException $e) {
            throw new LogsException($e);
        }

        try {
            if (!$this->work->lockExclusive()) {
                throw new LogsException("Problem while locking the file ". $this->workLogPath);
            }
        } catch (FileException $e) {
            throw new LogsException("dsf");
        }

        $this->updateProcessed();
        //sleep(5);

        $this->setExcFileNames();

        $this->work->movePointerToLine($this->processed+1);
        for ($ii=0; $ii<$this->processLimit; $ii++) {
            if (!($line = $this->work->getLine())) {
                break;
            }
            if (substr($line, 0, 1) == '[') {
                
                $timestamp = $this->retrieveDate($line);

                $logDate = $this->timestampToLogDate($timestamp);
                $logInfoArray = explode(":", substr($line, 23), 2); //split info
                $this->updateHashFile($logDate, $logInfoArray[1]);


                $this->clean->append($line);
            }
        }

        if ($ii<$this->processLimit) { //whole file read
            if (!$this->work->delete()) {
                throw new LogsException(sprintf(_("The log file cannot be processed correctly. Make sure the %s directory is writable."),$this->logDir));
            }
            $this->count->delete();
            return TRUE;
        } else {
            $this->work->releaseLock();
            return FALSE;
        }
    }

    /**
     * Another hash-function, oh my god... Well, this one gets the logDate and
     * logInfo (like its elder brother), but instead of getting, it inserts
     * the hash values into the hash-file. Everytime the "new" log is processed
     * (e.g. it has its "own" bluescreen file with its datetime), this method
     * generates record in the hash-file. The record is formated like
     * {hash}#{info}.
     *
     * @param <type> $logDate
     * @param <type> $logInfo
     * @return <type>
     */
    private function updateHashFile($logDate, $logInfo) {
        foreach ($this->excFileNames as $fileName) {
            if (substr($fileName, 10, 19) == $logDate) {
                $hash = substr($fileName, 30, 32);
                $this->hash->append($hash."#".$logInfo);
                return $hash;
            }
        }
    }



    private function moveDirtyToWork() {
        $this->dirty->move($this->workLogPath);
    }

    /**
     * Returns the number of already processed lines
     * @return int count of already processed lines
     */
    public function getProcessed() {
        if (empty($this->processed)) {
            return 0;
        } else return $this->processed;
    }

    /**
     * First, this function updates the class variable processed. The value
     * is read from the file $this->count inicialized in the processDirty()
     * method. Then it updates the value in the file (increases by the limit).
     * Returns void.
     */
    private function updateProcessed() {
        $this->processed = $this->count->getLine();
        $this->count->clear();
        $this->count->write($this->processed+$this->processLimit);
    }

    /**
     * Checks whether work or dirty log file exist
     * @return boolean TRUE when dirty OR work file exist
     */
    public function workOrDirtyExist() {
        try {
            return $this->initializeLogFile("work") || $this->initializeLogFile("dirty");
        } catch (LogsInitializeException $e) {
            throw new LogsException($e);
        }
    }


    /**
     * Initializes all log files needed to process it correctly. If the work
     * file exists, it loads it and process. Whether not, the function moves
     * the actual log file to the work file and then starts prcessing.
     */
    private function initializeLogFiles() {
        $this->initializeLogFile("dirty");
        $this->initializeLogFile("clean");
        $this->initializeLogFile("hash");
        $this->initializeLogFile("count");

        if (!$this->initializeLogFile("work")) { //work not existing
            $this->moveDirtyToWork();
            if (!$this->initializeLogFile("work")) { //this inicialization is important, dont delete it
                throw new LogsException(_("Log file cannot be initialized. This should never happen."));
            }
        }
    }


}